import java.awt.*;
import java.awt.geom.*;
import java.util.Date;

/**
* Ein Beispiel fuer eine Bewegung, die aus der Konvexkombination der
* Kontrollpunkte zweier Objekte (Buchstabe D und C) erzeugt wird.
*
* @author Frank Klawonn
* Letzte Aenderung 04.02.2005
*/
public class DToCMorphing extends Frame
{

  //Konstruktor
  public DToCMorphing()
  {
    //Ermoeglicht das Schliessen des Fensters
    addWindowListener(new MyFinishWindow());
  }


  public void paint(Graphics g)
  {

    Graphics2D g2d = (Graphics2D) g;

    //Verwendung von Antialiasing, um die Raender weniger ausgefranst
    //erscheinen zu lassen
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);

    //Die Linien sollen eine Dicke von 3.0 statt 1.0 haben.
    BasicStroke bs = new BasicStroke(5.0f);
    g2d.setStroke(bs);


    //Kontrollpunkte fuer den Buchstaben D
    int[] xd = new int[6]; //Der Index 0 wird nicht verwendet
    int[] yd = new int[6]; //Der Index 0 wird nicht verwendet

    xd[1] =  50;
    yd[1] =  50;

    xd[2] =  50;
    yd[2] = 450;

    xd[3] = 400;
    yd[3] = 250;

    xd[4] =  50;
    yd[4] = 450;

    xd[5] =  50;
    yd[5] = 250;


    //Kontrollpunkte fuer den Buchstaben C
    int[] xc = new int[6]; //Der Index 0 wird nicht verwendet
    int[] yc = new int[6]; //Der Index 0 wird nicht verwendet

    xc[1] =  50;
    yc[1] = 250;

    xc[2] = 250;
    yc[2] =  50;

    xc[3] =  50;
    yc[3] =  50;

    xc[4] =  250;
    yc[4] =  450;

    xc[5] =  50;
    yc[5] = 450;



    //Beide Buchstaben werden aus zwei quadratischen Kurven zusammengesetzt,
    //die als Kontrollpunkte den ersten, dritten und zweiten bzw. den ersten
    //fuenften und vierten Punkt verwenden.
    QuadCurve2D.Double q1;
    QuadCurve2D.Double q2;


    //Zeichne das D
    q1 = new QuadCurve2D.Double(xd[1],yd[1],xd[3],yd[3],xd[2],yd[2]);
    q2 = new QuadCurve2D.Double(xd[1],yd[1],xd[5],yd[5],xd[4],yd[4]);

    g2d.draw(q1);
    g2d.draw(q2);

    //Warte 1 Sekunde, bevor mit der Umwandlung von D nach C begonnen wird.
    sustain(1000);



    //Arrays, die die Konvexkombinationen der Kontrollpunkte von D und C
    //aufnehmen sollen
    double x[] = new double[xc.length];
    double y[] = new double[x.length];
    double alpha;

    //Anzahl der Zwischenschritte bei der Umwandlung von D nach C
    int steps = 500;
    double stepsDouble = steps; //Anzahl der Schritte als Double-Wert um
                                //dauerndes Casting in der Schleife zu vermeiden
    for (int i=1; i<=steps; i++)
    {
      alpha = i/stepsDouble;

      //Berechnung der Konvexkombinationen der fuenf Punktepaare
      for (int j=1; j<x.length; j++)
      {
        x[j] = (1-alpha)*xd[j] + alpha*xc[j];
        y[j] = (1-alpha)*yd[j] + alpha*yc[j];
      }

      //Erzeugung der beiden quadratischen Kurven, die durch die Kontrollpunkte
      //aus den Konvexkombinationen definiert werden.
      q1 = new QuadCurve2D.Double(x[1],y[1],x[3],y[3],x[2],y[2]);
      q2 = new QuadCurve2D.Double(x[1],y[1],x[5],y[5],x[4],y[4]);

      //Loeschen des Fensters
      clearWindow(g2d);

      //Zeichnen der beiden quadratischen Kurven
      g2d.draw(q1);
      g2d.draw(q2);

      //kurze Verzoegerung bis das naechste Bild gezeichnet wird
      sustain(10);

    }

  }




  /**
  * Eine Methode zum Loeschen (weiss malen) des Fensters.
  *
  * @param g2d      Graphics2D-Objekt, auf das gezeichnet werden soll.
  */
  public static void clearWindow(Graphics2D g)
  {
    g.setPaint(Color.white);
    g.fill(new Rectangle(0,0,270,470));
    g.setPaint(Color.black);
  }



  /**
  * Eine Methode, die eine Verzoegerung von t Millisekunden bewirkt.
  * Diese Methode wird hier nur verwendet, um das Programm moeglichst
  * einfach zu Halten. Sie hat jedoch rechenzeitintemsives aktives
  * Warten zur Folge. In realen Anwendungen sollte man Verzoegerungen
  * durch die Verwendung von Threads realisieren.
  *
  * @param t      Wartezeit in Millisekunden.
  */
  public static void sustain(long t)
  {
    long finish = (new Date()).getTime() + t;
    while( (new Date()).getTime() < finish ){}
  }



  public static void main(String[] argv)
  {
    DToCMorphing f = new DToCMorphing();
    f.setTitle("Wandlung D -> C");

    f.setSize(270,470);
    f.setVisible(true);
  }

}

